package com.zrkizzy.thread.practice;

import com.github.javafaker.Faker;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.Locale;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 打印机练习题
 *
 * <p>
 *     编写一个程序，模拟多个人在同时使用一台打印机。<br/>
 *     要求实现互斥访问打印机资源，确保同一时刻只有一个人可以打印。<br/>
 * </p>
 *
 * @author zhangrongkang
 * @since 2023/10/20
 */
public class PrinterPractice {

    /**
     * 使用打印机用户类
     */
    @Data
    @AllArgsConstructor
    static class User implements Runnable {

        /**
         * 用户名
         */
        private String name;

        /**
         * 打印机对象
         */
        private Printer printer;

        /**
         * 文档
         */
        private String document;

        /**
         * 用户使用打印机方法
         */
        @Override
        public void run() {
            printer.print(document, getName());
        }
    }

    /**
     * 打印机类
     */
    @Data
    @AllArgsConstructor
    static class Printer {

        private final ReentrantLock REENTRANT_LOCK = new ReentrantLock();

        /**
         * 打印文件方法
         *
         * @param document 文件名称
         * @param name 使用用户名称
         */
        public void print(String document, String name) {
            // 加锁
            REENTRANT_LOCK.lock();
            try {
                System.out.println(name + " 开始打印文件 " + document + " ......");
                try {
                    // 模拟打印过程
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("--------------- " + name + " 结束打印文件 " + document + " ---------------");
            } finally {
                // 释放锁
                REENTRANT_LOCK.unlock();
            }
        }
    }

    public static void main(String[] args) {
        Faker faker = new Faker(Locale.CHINA);

        // 创建一个打印机对象
        Printer printer = new Printer();


        // 创建多个人使用打印机
        User user = new User(faker.name().fullName(), printer, "文档Document1");
        User user1 = new User(faker.name().fullName(), printer, "文档Document2");
        User user2 = new User(faker.name().fullName(), printer, "文档Document3");
        User user3 = new User(faker.name().fullName(), printer, "文档Document4");
        User user4 = new User(faker.name().fullName(), printer, "文档Document5");
        User user5 = new User(faker.name().fullName(), printer, "文档Document6");

        user.run();
        user1.run();
        user2.run();
        user3.run();
        user4.run();
        user5.run();
    }
}
